﻿
using System;
using System.Collections.Generic;
using BaiTu.IQueueService.Providers;
using BaiTu.QueueEntity;
using BaiTu.IOCServices;

namespace BaiTu.QueueService
{
    public class QueueService : BaiTu.IQueueService.IQueue
    {
        /// <summary>
        /// 依赖注入一个队列提供者
        /// </summary>
        private IQueueProvider queueProvider = EngineContext.Current.Resolve<IQueueProvider>();
        /// <summary>
        /// 检查相应的队列是否存在 如不存在则自动重新建立
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void CreateIfNotExists<T>()
        {
            try
            {
                string queueName = QueueHelper.GetQueueName<T>();
                string responseQueueName = QueueHelper.GetResponseQueueName<T>();
                if (!queueProvider.IsQueueExists(queueName))
                    queueProvider.CreateQueue(queueName);
                if (!queueProvider.IsQueueExists(responseQueueName))
                    queueProvider.CreateQueue(responseQueueName);
            }
            catch (Exception ex)
            { 
            
            }
        }
        private static Dictionary<Type, bool> queueExistsMapping = new Dictionary<Type, bool>();
        private static object objLock_queueExistsMapping = new object();

        private void QueuePrepare<T>()
        {
            lock (objLock_queueExistsMapping)
            {
                try
                {
                    if (!queueExistsMapping.ContainsKey(typeof(T)))
                        queueExistsMapping.Add(typeof(T), false);
                    else if (queueExistsMapping[typeof(T)])
                        return;
                    CreateIfNotExists<T>();
                    queueExistsMapping[typeof(T)] = true;
                }
                catch (Exception ex)
                {

                }
            }
        }
        public string SendRequestToWorker<T>(QueueEntity.Message<T> message)
        {
            QueuePrepare<T>();
            string queueName = QueueHelper.GetQueueName<T>();
            InnerMessageWrapper msmqCmd = new InnerMessageWrapper();
            msmqCmd.Inject(message.Body);
            if (!string.IsNullOrWhiteSpace(message.ID))
            {
                msmqCmd.MessageID = message.ID;
            }
            queueProvider.SendMessage(queueName, msmqCmd);
            message.ID = msmqCmd.MessageID;
            return message.ID;
        }

        public string SendRequestToWorker<T>(T message, string messageID = null)
        {
            QueuePrepare<T>();

            Message<T> newMsg = new Message<T>();
            newMsg.Body = message;
            if (!string.IsNullOrEmpty(messageID))
            {
                newMsg.ID = messageID;
            }
            return SendRequestToWorker<T>(newMsg);

        }

        public QueueEntity.Message<T> GetRequestFromClient<T>()
        {
            QueuePrepare<T>();

            string queueName = QueueHelper.GetQueueName<T>();

            InnerMessageWrapper msmqCmd = queueProvider.ReceiveMessage(queueName);
            Message<T> msg = new Message<T>()
            {
                ID = msmqCmd.MessageID,
                Body = msmqCmd.Extract<T>()
            };

            return msg;
        }

        public void SendResponseToClient<T>(T message, string requestMessageID)
        {
            QueuePrepare<T>();

            string queueName = QueueHelper.GetResponseQueueName<T>();

            InnerMessageWrapper msmqCmd = new InnerMessageWrapper();
            msmqCmd.CorrelationID = requestMessageID;
            msmqCmd.Inject(message);

            queueProvider.SendMessage(queueName, msmqCmd);
        }

        public T GetResponseFromWorker<T>(string requestMessageID)
        {
            QueuePrepare<T>();

            string queueName = QueueHelper.GetResponseQueueName<T>();

            InnerMessageWrapper msmqCmd = queueProvider.ReceiveMessage(queueName, requestMessageID);

            return msmqCmd.Extract<T>();
        }
    }
}
